/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package de.hwr.nbaplan.server.dataload;

import de.hwr.nbaplan.shared.model.Kurs;
import de.hwr.nbaplan.server.loadData;
import de.hwr.nbaplan.shared.model.Modul;
import de.hwr.nbaplan.shared.model.Studiengang;
import de.hwr.nbaplan.shared.model.Vorlesung;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.ComponentList;
import net.fortuna.ical4j.model.component.VEvent;

/**
 *
 * @author flo
 */
public class ICSLoader {

    private URL url;
    private EntityManagerFactory emf = Persistence.createEntityManagerFactory("NBA-PlanPU");
    private int statAdded = 0;
    private int statDeleted = 0;
    private int statInCal = 0;
    private static final int AGE_AT_REMOVE = 30;
    private Kurs kurs;
    private String iscfilename;

    /**
     *
     */
    public ICSLoader() {
    }

    /**
     *
     * @param kurs
     */
    public ICSLoader(Kurs kurs) {
        this(kurs.getFStudiengang(), kurs);
    }

    /**
     *
     * @param studiengang
     * @param kurs
     */
    public ICSLoader(Studiengang studiengang, Kurs kurs) {
        try {
            this.kurs = kurs;
            url = new URL(studiengang.getICSUrl(kurs));
            //url = new URL("http://taft-mueller.de/kursa.ics");
        } catch (MalformedURLException ex) {
            Logger.getLogger(ICSLoader.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     *
     * @return
     * @throws IOException
     */
    public String loadPlan() throws IOException {

        String lineSep = System.getProperty("line.separator");
        BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), "UTF8"));

        String inputLine = "";

        StringBuilder sb = new StringBuilder();
        while ((inputLine = in.readLine()) != null) {
            sb.append(inputLine);
            sb.append(lineSep);
        }
        in.close();


        return sb.toString();
    }

    /**
     *
     * @param path
     */
    public void loadPlanAsFile(String path)  {
        BufferedInputStream in = null;
        FileOutputStream fos=null;
        BufferedOutputStream bout=null;
        try {
            in = new BufferedInputStream(url.openStream());
            this.iscfilename = path+"/"+kurs.getFStudiengang().getKurzform() + kurs.getSemester() + kurs.getKursChar() + (Math.round(Math.random() * 1000)) + ".ics";
             fos = new FileOutputStream(this.iscfilename);
             //System.out.println(new File(this.iscfilename).getAbsoluteFile());
             bout = new BufferedOutputStream(fos, 1024);
            byte[] data = new byte[1024];
            int count;
            while ((count = in.read(data, 0, 1024)) != -1) {
                bout.write(data, 0, count);
            }
           
        } catch (IOException ex) {
            Logger.getLogger(ICSLoader.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                  bout.close();
                fos.close();
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(ICSLoader.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     *
     * @param kurs
     * @throws IOException
     */
    public void parse( Kurs kurs) throws IOException {
         parse(this.loadPlan(),kurs);
     }

    /**
     *
     * @param TextToParse
     * @param kurs
     */
    public void parse(String TextToParse, Kurs kurs) {
        //loadPlanAsFile(loadData.TEMP_PATH);
        try {
            java.util.Calendar dataload = new GregorianCalendar();
            //FileInputStream fin = new FileInputStream(iscfilename);
            StringReader sin = new StringReader(TextToParse);
            CalendarBuilder builder = new CalendarBuilder();
            Calendar calendar = new Calendar();
            calendar = builder.build(sin);
            ComponentList cl = calendar.getComponents();
            //check last event
            VEvent lastEvent = (VEvent) cl.get(cl.size() - 1);
            int age = calcAge(lastEvent);

            Iterator<VEvent> it = cl.iterator();
            Long addid = new Long(Math.round(Math.floor(10000 * Math.random()) + 1));
            while (it.hasNext()) {
                VEvent event = it.next();
                java.util.Calendar start = new GregorianCalendar();
                start.setTime(event.getStartDate().getDate());
                java.util.Calendar ende = new GregorianCalendar();
                ende.setTime(event.getEndDate().getDate());

                Vorlesung vor = new Vorlesung(event.getSummary().getValue(), start, ende, event.getLocation().getValue(), event.getDescription().getValue(), dataload);

                // vorlesungen.add(vor);
                Modul m = this.getModul(vor, kurs);
                if (m.getVorlesungCollection() == null) {
                    m.setVorlesungCollection(new LinkedList<Vorlesung>());
                }

                boolean old = false;
                //überprüfe ob vorlesung alt ist.
                for (Vorlesung v : m.getVorlesungCollection()) {

                    if (v.equalsNameBeginnEnde(vor)) {
                        if (v.isDeleted()) {
                            vor.setDeleted(new Short("0"));
                            vor.setDeleteddate(null);
                            update(vor);
                        }
                        old = true;
                        v.setGefunden(true);
                        break;
                    }
                }
                //neue vorlesung die nicht im plan war vorher
                if (!old) {
                    vor.setGefunden(true);
                    m.getVorlesungCollection().add(vor);
                    vor.setAdded(new Short("1"));
                    vor.setFModul(m);
                    m.getVorlesungCollection().add(vor);
                    this.persist(vor);
                    this.statAdded++;
                }
            }
            //lösche alte einträge
            for (Modul modul : kurs.getModulCollection()) {
                for (Vorlesung vor : modul.getVorlesungCollection()) {
                    if (!vor.isGefunden()) {
                        if (!vor.isDeleted()) {
                            if (vor.getBeginn().after(new GregorianCalendar())) {
                                this.statDeleted++;
                                vor.setDeleted(new Short("1"));
                                vor.setDeleteddate(new GregorianCalendar());
                                update(vor);
                            }
                        } else {
                            this.statInCal--;
                        }

                    }
                }
                this.statInCal += modul.getVorlesungCollection().size();
            }
            this.statInCal -= this.statDeleted;
            this.statInCal -= this.statAdded;
        } catch (IOException ex) {
            Logger.getLogger(ICSLoader.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserException ex) {
            Logger.getLogger(ICSLoader.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
            //new File(iscfilename).delete();
        }

    }

    /**
     *
     * @param vor
     * @param kurs
     * @return
     */
    public Modul getModul(Vorlesung vor, Kurs kurs) {

        List<Modul> list = (List<Modul>) kurs.getModulCollection();
        if (list == null) {
            return null;
        }
        for (Modul m : list) {
            if (m.getName().equals(vor.getName()) && m.getProf().equals(vor.getProfessor())) {
                return m;
            }
        }

        Modul m = new Modul(vor.getName(), vor.getProfessor(), kurs);
        kurs.getModulCollection().add(m);
        this.persist(m);
        return m;
    }

    /**
     *
     * @param object
     */
    public void update(Object object) {
        EntityManager em = emf.createEntityManager();
        try {
            em.getTransaction().begin();
            em.merge(object);
            em.getTransaction().commit();
        } catch (Exception e) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", e);
            em.getTransaction().rollback();
        } finally {
            em.close();
        }
    }

    /**
     *
     * @param object
     */
    public void persist(Object object) {
        EntityManager em = emf.createEntityManager();
        try {
            em.getTransaction().begin();
            em.persist(object);
            em.getTransaction().commit();
        } catch (Exception e) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", e);
            em.getTransaction().rollback();
        } finally {
            em.close();
        }
    }

    /**
     * @return the statAdded
     */
    public int getStatAdded() {
        return statAdded;
    }

    /**
     * @return the statDeleted
     */
    public int getStatDeleted() {
        return statDeleted;
    }

    /**
     * @return the statInCal
     */
    public int getStatInCal() {
        return statInCal;
    }

    private int calcAge(VEvent lastEvent) {
        java.util.Calendar start = new GregorianCalendar();
        start.setTime(lastEvent.getStartDate().getDate());
        return (int) ((new GregorianCalendar().getTimeInMillis() - (start.getTimeInMillis())) / 86400000);

    }
}
